package com.jboltai.config;

import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.Setting;
import cn.hutool.setting.SettingUtil;
import com.alibaba.fastjson.JSON;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class JBoltAIConfig {
    public static final String VERSION = "4.1.0";

    public static void main(String[] args) {
        System.out.println(JBOLT_AI_NAME_STR);
    }
    public static final String LOGGER_NAME = "com.jboltai";
    public static final String JBOLT_AI_NAME_STR = "       _ ____        _ _            _____ \n" +
            "      | |  _ \\      | | |     /\\   |_   _|\n" +
            "      | | |_) | ___ | | |_   /  \\    | |  \n" +
            "  _   | |  _ < / _ \\| | __| / /\\ \\   | |  \n" +
            " | |__| | |_) | (_) | | |_ / ____ \\ _| |_ \n" +
            "  \\____/|____/ \\___/|_|\\__/_/    \\_\\_____|\n" +
            "                                          ";

    /**
     * http请求的读取超时，单位ms
     */
    private static String HTTP_READ_TIMEOUT = "httpReadTimeout";

    /**
     * http请求的写入超时，单位ms
     */
    private static final String HTTP_WRITE_TIMEOUT = "httpWriteTimeout";

    /**
     * 同一个域名，同一个httpclient可以并发执行的请求数，超过的就会进等待队列
     */
    private static final String MAX_ASYNC_REQUEST_PER_HOST = "maxAsyncRequestPerHost";
    /**
     * 同一个httpclient可以并发执行的请求数，超过的就会进等待队列
     */
    private static final String MAX_ASYNC_REQUEST_PER_CLIENT = "maxAsyncRequestPerClient";

    /**
     * AI事件队列最大等待数量，达到这个数量就会直接拒绝新的事件
     */
    private static final String MAX_AIEVENT_WAIT_COUNT = "maxAIEventWaitCount";
    /**
     * 事件等待执行的超时时间，单位ms
     */
    private static final String MAX_AIEVENT_WAIT_TIMEOUT = "maxAIEventWaitTimeout";

    /**
     * Embedding事件队列最大等待数量，达到这个数量就会直接拒绝新的事件
     */
    private static final String MAX_EMBEDDING_EVENT_WAIT_COUNT = "maxEmbeddingEventWaitCount";

    /**
     * text事件最大等待数量
     */
    private static final String MAX_TEXT_EVENT_WAIT_COUNT = "maxTextEventWaitCount";

    /**
     * text事件等待执行的超时时间，单位ms
     */
    private static final String MAX_TEXT_EVENT_WAIT_TIMEOUT = "maxTextEventWaitTimeout";

    /**
     * text事件最大处理线程数
     */
    private static final String MAX_TEXT_EVENT_THREAD_COUNT = "maxTextEventThreadCount";

    /**
     * 默认文本分段大小，单位是token，一般一个英文单词算1.3token，其他字符都算1token
     */
    private static final String DEFAULT_TEXT_CHUNK_SIZE = "defaultTextChunkSize";

    /**
     * 文本分段默认重叠大小，单位token
     */
    private static final String DEFAULT_TEXT_CHUNK_OVERLAP = "defaultTextChunkOverlap";

    /**
     * 文本分段默认分割符
     */
    private static final String DEFAULT_TEXT_CHUNK_SEPARATOR = "defaultTextChunkSeparator";


    /**
     * 知识库没匹配时的默认回复
     */
    private static final String DEFAULT_REPLY_WHEN_NO_MATCH_KNOWLEDGE = "defaultReplyWhenNoMatchKnowledge";

    private static String LOG_ENABLE = "log_enable";

    private static final HashMap<String, Object> config = new HashMap<>();


    public static void loadFromConfigFile(String configFile) {
        if (StrUtil.isBlank(configFile)) {
            throw new RuntimeException("配置文件路径不能为空");
        }
        Setting allSetting = SettingUtil.get(configFile);
        if (allSetting == null) {
            throw new RuntimeException("无法加载配置文件: " + configFile);
        }

        // 加载HTTP相关配置

        setValue(HTTP_READ_TIMEOUT, allSetting.getInt(HTTP_READ_TIMEOUT));
        setValue(HTTP_WRITE_TIMEOUT, allSetting.getInt(HTTP_WRITE_TIMEOUT));
        setValue(MAX_ASYNC_REQUEST_PER_HOST, allSetting.getInt(MAX_ASYNC_REQUEST_PER_HOST));
        setValue(MAX_ASYNC_REQUEST_PER_CLIENT, allSetting.getInt(MAX_ASYNC_REQUEST_PER_CLIENT));

        // 加载AI事件相关配置

        setValue(MAX_AIEVENT_WAIT_COUNT, allSetting.getInt(MAX_AIEVENT_WAIT_COUNT));
        setValue(MAX_AIEVENT_WAIT_TIMEOUT, allSetting.getInt(MAX_AIEVENT_WAIT_TIMEOUT));
        setValue(MAX_EMBEDDING_EVENT_WAIT_COUNT, allSetting.getInt(MAX_EMBEDDING_EVENT_WAIT_COUNT));

        // 加载文本事件相关配置

        setValue(MAX_TEXT_EVENT_WAIT_COUNT, allSetting.getInt(MAX_TEXT_EVENT_WAIT_COUNT));
        setValue(MAX_TEXT_EVENT_WAIT_TIMEOUT, allSetting.getInt(MAX_TEXT_EVENT_WAIT_TIMEOUT));
        setValue(MAX_TEXT_EVENT_THREAD_COUNT, allSetting.getInt(MAX_TEXT_EVENT_THREAD_COUNT));

        // 加载文本分段相关配置

        setValue(DEFAULT_TEXT_CHUNK_SIZE, allSetting.getInt(DEFAULT_TEXT_CHUNK_SIZE));
        setValue(DEFAULT_TEXT_CHUNK_OVERLAP, allSetting.getInt(DEFAULT_TEXT_CHUNK_OVERLAP));
        String separators = allSetting.getStr(DEFAULT_TEXT_CHUNK_SEPARATOR);
        if (separators != null) {
            setValue(DEFAULT_TEXT_CHUNK_SEPARATOR, JSON.parseArray(separators).toArray(new String[0]));
        }

        // 加载其他配置

        setValue(DEFAULT_REPLY_WHEN_NO_MATCH_KNOWLEDGE, allSetting.getStr(DEFAULT_REPLY_WHEN_NO_MATCH_KNOWLEDGE));
        if (allSetting.containsKey(LOG_ENABLE)) {
            setLogEnable(allSetting.getBool(LOG_ENABLE));
        }
    }


    public static void reload(Map<String, Object> config) {
        if (config == null || config.isEmpty()) return;

        Iterator<String> iterator = config.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            Object value = config.get(key);
            setValue(key, value);
        }

    }


    /**
     * 获取值
     * @param key
     * @param type
     * @param defaultValue
     * @return
     * @param <T>
     */
    public static <T> T getValue(String key, Class<T> type, T defaultValue) {
        Object value = config.get(key);
        if (value == null) {
            return defaultValue;
        }
        if (type.isInstance(value)) {
            return (T) value;
        }
        if (type == String.class) {
            return (T) value.toString();
        }
        if (type == Integer.class) {
            return (T) Integer.valueOf(value.toString());
        }

        if (type == Double.class) {
            return (T) Double.valueOf(value.toString());
        }

        if (type == Long.class) {
            return (T) Long.valueOf(value.toString());
        }

        if (type == Boolean.class) {
            return (T) Boolean.valueOf(value.toString().equals("true") ? true : false);
        }
        if (type == String[].class) {
            return (T) value.toString().split("_");
        }

        throw new IllegalArgumentException("不支持的类型:"+type);
    }

    /**
     * 设置配置项的值
     * @param key
     * @param value
     */
    private synchronized static void setValue(String key, Object value) {
        config.put(key, value);
    }

    /**
     * 获取http请求的读取超时，单位ms
     * @return
     */
    public static int getHttpReadTimeout() {
        return getValue(HTTP_READ_TIMEOUT,Integer.class, 60000);
    }

    public static void setHttpReadTimeout(int value) {
        setValue(HTTP_READ_TIMEOUT, value);
    }

    public static boolean getLogEnable() {
        return getValue(LOG_ENABLE, Boolean.class, true);
    }

    public static void setLogEnable(boolean enable) {
        setValue(LOG_ENABLE, enable);
        if (enable) {
            Configurator.setLevel(LOGGER_NAME, Level.DEBUG);
        } else {
            Configurator.setLevel(LOGGER_NAME, Level.OFF);
        }
    }



    /**
     * 获取http请求的写入超时，单位ms
     * @return
     */
    public static int getHttpWriteTimeout() {
        return getValue(HTTP_WRITE_TIMEOUT,Integer.class, 30000);
    }

    /**
     * 设置http请求的写入超时，单位ms
     * @param value
     */
    public static void setHttpWriteTimeout(int value) {
        setValue(HTTP_WRITE_TIMEOUT, value);
    }


    /**
     * 同一个域名，同一个httpclient可以并发执行的请求数，超过的就会进等待队列
     * @return
     */
    public static int getMaxAsyncRequestPerHost() {
        return getValue(MAX_ASYNC_REQUEST_PER_HOST,Integer.class, 100);
    }


    /**
     * 设置同一个域名，同一个httpclient可以并发执行的请求数，超过的就会进等待队列
     * @param value
     */
    public static void setMaxAsyncRequestPerHost(int value) {
        setValue(MAX_ASYNC_REQUEST_PER_HOST, value);
    }



    /**
     * 同一个httpclient可以并发执行的请求数，超过的就会进等待队列
     * @return
     */
    public static int getMaxAsyncRequestPerClient() {
        return getValue(MAX_ASYNC_REQUEST_PER_CLIENT,Integer.class, 100);
    }

    /**
     * 设置同一个httpclient可以并发执行的请求数，超过的就会进等待队列
     * @param value
     */
    public static void setMaxAsyncRequestPerClient(int value) {
        setValue(MAX_ASYNC_REQUEST_PER_CLIENT, value);
    }


    /**
     * AI事件队列最大等待数量，达到这个数量就会直接拒绝新的事件
     * @return
     */
    public static int getMaxAIEventWaitCount() {
        return getValue(MAX_AIEVENT_WAIT_COUNT,Integer.class, 200);
    }

    /**
     * 设置AI事件队列最大等待数量，达到这个数量就会直接拒绝新的事件
     * @param value
     */
    public static void setMaxAIEventWaitCount(int value) {
        setValue(MAX_AIEVENT_WAIT_COUNT, value);
    }


    /**
     * 事件等待执行的超时时间，单位ms
     * @return
     */
    public static int getMaxAIEventWaitTimeout() {
        return getValue(MAX_AIEVENT_WAIT_TIMEOUT,Integer.class, 30000);
    }

    /**
     * 设置事件等待执行的超时时间，单位ms
     * @param value
     */
    public static void setMaxAIEventWaitTimeout(int value) {
        setValue(MAX_AIEVENT_WAIT_TIMEOUT, value);
    }

    /**
     * Embedding事件队列最大等待数量，达到这个数量就会直接拒绝新的事件
     * @return
     */
    public static int getMaxEmbeddingEventWaitCount() {
        return getValue(MAX_EMBEDDING_EVENT_WAIT_COUNT,Integer.class, 3000);
    }

    /**
     * 设置Embedding事件队列最大等待数量，达到这个数量就会直接拒绝新的事件
     * @param value
     */
    public static void setMaxEmbeddingEventWaitCount(int value) {
        setValue(MAX_EMBEDDING_EVENT_WAIT_COUNT, value);
    }


    /**
     * 文本事件最大等待数量
     * @return
     */
    public static int getMaxTextEventWaitCount() {
        //1000个文本，如果按照每个500token算，大概20M内存占用
        return getValue(MAX_TEXT_EVENT_WAIT_COUNT,Integer.class, 3000);
    }

    /**
     * 设置文本事件最大等待数量
     * @param value
     */
    public static void setMaxTextEventWaitCount(int value) {
        setValue(MAX_TEXT_EVENT_WAIT_COUNT, value);
    }

    /**
     * 文本事件最大处理线程数
     * @return
     */
    public static int getMaxTextEventThreadCount() {

        return getValue(MAX_TEXT_EVENT_THREAD_COUNT,Integer.class, 5);
    }

    /**
     * 设置文本事件最大处理线程数
     * @param value
     */
    public static void setMaxTextEventThreadCount(int value) {
        setValue(MAX_TEXT_EVENT_THREAD_COUNT, value);
    }


    /**
     * 文本事件等待执行的超时时间，单位ms
     * @return
     */
    public static int getMaxTextEventWaitTimeout() {
        return getValue(MAX_TEXT_EVENT_WAIT_TIMEOUT,Integer.class, 60000);
    }

    /**
     * 设置文本事件等待执行的超时时间，单位ms
     * @param value
     */
    public static void setMaxTextEventWaitTimeout(int value) {
        setValue(MAX_TEXT_EVENT_WAIT_TIMEOUT, value);
    }

    /**
     * 默认文本分段大小
     * @return
     */
    public static int getDefaultTextChunkSize() {
        return getValue(DEFAULT_TEXT_CHUNK_SIZE,Integer.class, 500);
    }

    /**
     * 设置默认文本分段大小
     * @param value
     */
    public static void setDefaultTextChunkSize(int value) {
        setValue(DEFAULT_TEXT_CHUNK_SIZE, value);
    }

    /**
     * 文本分段默认重叠大小
     * @return
     */
    public static int getDefaultTextChunkOverlap() {
        return getValue(DEFAULT_TEXT_CHUNK_OVERLAP,Integer.class, 100);
    }

    /**
     * 设置文本分段默认重叠大小
     * @param value
     */
    public static void setDefaultTextChunkOverlap(int value) {
        setValue(DEFAULT_TEXT_CHUNK_OVERLAP, value);
    }

    /**
     * 文本分段默认分割符
     * @return
     */
    public static String[] getDefaultTextChunkSeparator() {
        return getValue(DEFAULT_TEXT_CHUNK_SEPARATOR, String[].class, new String[]{"\n", "。"});
    }

    /**
     * 设置文本分段默认分割符
     * @param value
     */
    public static void setDefaultTextChunkSeparator(String[] value) {
        setValue(DEFAULT_TEXT_CHUNK_SEPARATOR, value);
    }

    /**
     * 知识库没匹配时的默认回复
     * @return
     */
    public static String getDefaultReplyWhenNoMatchKnowledge() {
        return getValue(DEFAULT_REPLY_WHEN_NO_MATCH_KNOWLEDGE, String.class, "抱歉，我暂时无法回答您的这个问题。");
    }

    /**
     * 设置知识库没匹配时的默认回复
     * @param value
     */
    public static void setDefaultReplyWhenNoMatchKnowledge(String value) {
        setValue(DEFAULT_REPLY_WHEN_NO_MATCH_KNOWLEDGE, value);
    }


}
